package wml.clipstore.map;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import wml.clipstore.base.Entity;
import wml.clipstore.base.Identifier;
import wml.clipstore.utils.EntityUtils;

public class MapManager {

	@SuppressWarnings("rawtypes")
	private static List<Class> storableType = new ArrayList<Class>();
	private static MapManager manager;
	private Map<Class<? extends Entity>, List<Field>> storableFields = new HashMap<Class<? extends Entity>, List<Field>>();
	private List<String> templates;
	static{
		storableType.add(String.class);
		storableType.add(Number.class);
		storableType.add(Boolean.class);
		storableType.add(Character.class);

		storableType.add(Identifier.class);
		storableType.add(Entity.class);
		storableType.add(Collection.class);
	}
	
	private MapManager() {
		loadClasses();
	}

	private void loadClasses(){
		try {
			String collection = "(deftemplate Collection (slot identifier) (multislot items))";
			this.templates = this.toDeftemplates(Interpreter.getClasses());
			this.templates.add(collection);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	private boolean isStorable(Field field) {
		Class<?> type = field.getType();
		if (type.isPrimitive())
			return true;
		for (Class<?> clazz : storableType) {
			if (EntityUtils.isSubClass(type, clazz))
				return true;
		}
		return false;
	}

	public static MapManager getInstance(){
		if (manager == null)
			manager = new MapManager();
		return manager;
	}

	public List<String> toDeftemplates(Class<? extends Entity>... classes) {
		return this.toDeftemplates(classes);
	}

	public List<String> toDeftemplates(List<Class<? extends Entity>> classes) {
		List<String> templates = new ArrayList<String>();
		for (Class<? extends Entity> clazz : classes) {
			String template = this.toDeftemplate(clazz);
			templates.add(template);
		}
		return templates;
	}

	public String toDeftemplate(Class<? extends Entity> clazz) {
		List<Field> storableFields = new ArrayList<Field>();
		String deftemplate = "(deftemplate " + clazz.getName();
		List<Field> fields = EntityUtils.getFields(clazz);
		for (Field f : fields) {
			if (this.isStorable(f)) {
				storableFields.add(f);
				deftemplate += " (slot " + f.getName() + ")";
			}
		}
		if (!this.storableFields.containsKey(clazz))
			this.storableFields.put(clazz, storableFields);
		return deftemplate + ")";
	}

	public List<String> getTemplates(){
		return this.templates;
	}
	
	public Set<Class<? extends Entity>> getStoredEntities() {
		return this.storableFields.keySet();
	}
	
	public List<Field> getStoredFields(Class<? extends Entity> clazz) {
		return this.storableFields.get(clazz);
	}
}
